﻿using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Huasky.Jwt;

public class JwtUserInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
    public string Role { get; set; }
}

public class JwtHelper
{
    /// <summary>
    /// 颁发JWT
    /// </summary>
    /// <param name="tokenModel">当前颁发对象的用户信息</param>
    /// <returns>JWT字符串</returns>
    public static string IssueJwt(JwtUserInfo jwtUserInfo)
    {

        #region 【Step1-从配置文件中获取生成JWT所需要的数据】
        string iss = Appsettings.GetVal(["Audience", "Issuer"]);//颁发者
        string aud = Appsettings.GetVal(["Audience", "Audience"]);//使用者
        string secret = Appsettings.GetVal(["Audience", "Secret"]); //密钥
        #endregion

        #region 【Step2-通过Claim创建JWT中的Payload(载荷)信息】

        var claimsIdentity = new List<Claim>
                {
                 new(JwtRegisteredClaimNames.Jti, jwtUserInfo.Id.ToString()), //JWT ID
                 new(JwtRegisteredClaimNames.Name, jwtUserInfo.Name), //JWT name
                 new("code", jwtUserInfo.Code), //JWT code
                new(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),//JWT的发布时间
                new(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddDays(7)).ToUnixTimeSeconds()}"),//JWT到期时间
                new(JwtRegisteredClaimNames.Iss,iss), //颁发者
                new(JwtRegisteredClaimNames.Aud,aud)//使用者
               };

        //添加用户的角色信息（非必须，可添加多个）
        var claimRoleList = jwtUserInfo.Role.Split(',').Select(role => new Claim(ClaimTypes.Role, role)).ToList();
        claimsIdentity.AddRange(claimRoleList);
        #endregion

        #region 【Step3-签名对象】

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); //创建密钥对象
        var sigCreds = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); //创建密钥签名对象

        #endregion

        #region 【Step5-将JWT相关信息封装成对象】
        var jwt = new JwtSecurityToken(
          issuer: iss,
          claims: claimsIdentity,
          signingCredentials: sigCreds);
        #endregion

        #region 【Step6-将JWT信息对象生成字符串形式】
        var jwtHandler = new JwtSecurityTokenHandler();
        string token = jwtHandler.WriteToken(jwt);
        #endregion

        return token;
    } // END IssueJwt()

    /// <summary>
    /// 将JWT加密的字符串进行解析
    /// </summary>
    /// <param name="jwtStr">JWT加密的字符</param>
    /// <returns>JWT中的用户信息</returns>
    public static JwtUserInfo SerializeJwtStr(string jwtStr)
    {
        var jwtUserInfo = new JwtUserInfo();
        var jwtHandler = new JwtSecurityTokenHandler();

        if (!string.IsNullOrEmpty(jwtStr) && jwtHandler.CanReadToken(jwtStr))
        {
            //将JWT字符读取到JWT对象
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);

            //获取JWT中的用户信息
            jwtUserInfo.Id = Convert.ToInt32(jwtToken.Id);
            jwtToken.Payload.TryGetValue(ClaimTypes.Role, out object role); //获取角色信息
            jwtUserInfo.Role = role == null ? "" : role.ToString();
        }

        return jwtUserInfo;
    } //END SerializeJwt()


}
